package com.ysy.lock;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: zookeeper-demo
 * @description: 并发测试工具
 * @author: yeshiyuan
 * @create: 2019-06-13 19:56
 **/
public class ConcurrentTest {

    private CyclicBarrier cyclicBarrier = null;
    private CopyOnWriteArrayList<Long> list = new CopyOnWriteArrayList<Long>();
    private AtomicInteger atomicInteger = new AtomicInteger(); //原子递增
    private ConcurrentTask[] task = null;
    private CountDownLatch endSignal = null; //开始阀门

    public ConcurrentTest(ConcurrentTask... task) {
        this.task = task;
        if (task == null) {
            System.out.println("task can not null");
            System.exit(1);
        }
        cyclicBarrier = new CyclicBarrier(task.length, new Runnable() {
            public void run() {
                //计算执行时间
                //getExeTime();
                System.out.println("所有线程已初始化好，开始抢占锁");
            }
        });
        endSignal = new CountDownLatch(task.length);
    }

    public interface ConcurrentTask {
        void run();
    }

    public void start() {
        //创建线程，并将所有线程等待在阀门处
        createThread();
        //打开阀门,如果计数到达零，则释放所有等待的线程
        //startSignal.countDown();
        /*try {
            doneSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        try {
            endSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        getExeTime();
    }

    private void createThread() {
        for (int i = 0; i < task.length; i++) {
            final int j = i;
            new Thread(new Runnable() {
                public void run() {
                    try {
                        cyclicBarrier.await();
                        //startSignal.await();//使当前线程在锁存器倒计数至零之前一直等待
                        long start = System.currentTimeMillis();
                        task[j].run();
                        long end = System.currentTimeMillis();
                        list.add(end - start);

                    } catch (InterruptedException e) {
                        atomicInteger.getAndIncrement();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    } finally {
                        endSignal.countDown();
                    }
                }
            }).start();
        }
    }

    /**
     * 计算平均响应时间
     */
    private void getExeTime() {
        int size = list.size();
        List<Long> _list = new ArrayList<Long>(size);
        _list.addAll(list);
        Collections.sort(_list);
        long min = _list.get(0);
        long max = _list.get(size-1);
        long sum = 0L;
        for (Long t : _list) {
            sum += t;
        }
        long avg = sum/size;
        System.out.println("min: " + min);
        System.out.println("max: " + max);
        System.out.println("avg: " + avg);
        System.out.println("err: " + atomicInteger.get());
    }
}
